﻿using Microsoft.Data.SqlClient;
using System.Transactions;

namespace 用TransactionScope实现一个分布式事务
{
    internal class Program
    {
        // 数据库1连接字符串（示例：订单数据库）
        private const string OrderDbConnectionString =
            "Data Source=.;Initial Catalog=OrderDB;Integrated Security=True;";

        // 数据库2连接字符串（示例：库存数据库）
        private const string InventoryDbConnectionString =
            "Data Source=.;Initial Catalog=InventoryDB;Integrated Security=True;";

        static void Main(string[] args)
        {
            try
            {
                // 执行分布式事务
                bool isSuccess = ExecuteDistributedTransaction(
                    orderId: 1001,
                    productId: 500,
                    quantity: 10
                );

                if (isSuccess)
                {
                    Console.WriteLine("分布式事务执行成功：订单创建和库存扣减均完成");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"分布式事务失败：{ex.Message}");
            }
        }

        /// <summary>
        /// 执行跨数据库的分布式事务
        /// 场景：创建订单（订单库）+ 扣减库存（库存库）
        /// </summary>
        /// <param name="orderId">订单ID</param>
        /// <param name="productId">商品ID</param>
        /// <param name="quantity">购买数量</param>
        /// <returns>事务是否成功</returns>
        static bool ExecuteDistributedTransaction(int orderId, int productId, int quantity)
        {
            // 1. 创建TransactionScope，自动管理分布式事务
            // - TransactionScopeOption.Required：如果已有事务则加入，否则创建新事务
            // - 超时时间设置为30秒（根据业务需求调整）
            using (var scope = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions { Timeout = TimeSpan.FromSeconds(30) }))
            {
                try
                {
                    // 2. 操作第一个数据库：创建订单
                    CreateOrder(orderId, productId, quantity);

                    // 3. 操作第二个数据库：扣减库存
                    DeductInventory(productId, quantity);

                    // 4. 所有操作成功，提交事务（分布式事务协调器会通知所有参与方提交）
                    scope.Complete();
                    return true;
                }
                catch (Exception)
                {
                    // 5. 若发生异常，不调用Complete()，using会自动回滚事务
                    // （分布式事务协调器会通知所有参与方回滚）
                    throw; // 向上抛出异常，由调用方处理
                }
            }
        }

        /// <summary>
        /// 在订单数据库创建订单记录
        /// </summary>
        static void CreateOrder(int orderId, int productId, int quantity)
        {
            using (var conn = new SqlConnection(OrderDbConnectionString))
            {
                conn.Open(); // 打开连接时会自动加入当前分布式事务

                string sql = @"
                INSERT INTO Orders (OrderId, ProductId, Quantity, CreateTime)
                VALUES (@OrderId, @ProductId, @Quantity, GETDATE())";

                using (var cmd = new SqlCommand(sql, conn))
                {
                    cmd.Parameters.AddWithValue("@OrderId", orderId);
                    cmd.Parameters.AddWithValue("@ProductId", productId);
                    cmd.Parameters.AddWithValue("@Quantity", quantity);
                    cmd.ExecuteNonQuery();
                }
            }
        }

        /// <summary>
        /// 在库存数据库扣减库存
        /// </summary>
        static void DeductInventory(int productId, int quantity)
        {
            using (var conn = new SqlConnection(InventoryDbConnectionString))
            {
                conn.Open(); // 打开连接时会自动加入当前分布式事务

                string sql = @"
                UPDATE Inventory 
                SET Stock = Stock - @Quantity 
                WHERE ProductId = @ProductId 
                AND Stock >= @Quantity"; // 确保库存充足

                using (var cmd = new SqlCommand(sql, conn))
                {
                    cmd.Parameters.AddWithValue("@ProductId", productId);
                    cmd.Parameters.AddWithValue("@Quantity", quantity);
                    int affectedRows = cmd.ExecuteNonQuery();

                    // 如果没有更新任何行，说明库存不足，抛出异常触发回滚
                    if (affectedRows == 0)
                    {
                        throw new InvalidOperationException($"商品ID {productId} 库存不足，无法扣减");
                    }
                }
            }
        }
    }
}
